package com.fxb.mocker.utils.bean;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.TreeSet;

import org.springframework.util.ReflectionUtils;

import com.fxb.mocker.utils.random.RandomUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

import lombok.extern.slf4j.Slf4j;

/**
 * 创建Bean util
 *
 * @author fangjiaxiaobai
 * @date 2021-02-20 12:20
 * @since 1.0.0
 */
@Slf4j
public class NewBeanUtil {

    /**
     * 创建对象
     *
     * @param tClass 对象的类型
     * @param <T>    类型
     *
     * @return 对象
     */
    public static <T> T newInstance(Method method, Class<T> tClass, Field field) throws Exception {

        // 判断是否为数组
        boolean isArray = tClass.isArray();
        if (isArray) {
            System.out.println("isArray");
            return doParseArray(method, tClass, field);
        }
        // 判断是否为集合
        else if (Collection.class.isAssignableFrom(tClass)) {
            System.out.println("isCollection");
            return doParseCollection(method, tClass, field);
        } else if (Map.class.isAssignableFrom(tClass)) {
            System.out.println("isCollection");
            return doParseMap(tClass);
        }
        // 判断是否为接口
        else if (tClass.isInterface()) {
            System.out.println("isInterface");
            return doParseInterface(tClass);
        }
        // 判断是否为简单类型:(基本类型,包装类型,时间类型,String)
        if (BeanTypeUtil.isSimpleField(tClass)) {
            return (T) BeanTypeUtil.getSimpleFieldValue(tClass);
        } else {
            // 如果是自定义类,则获取是否有父类
            Constructor<?>[] declaredConstructors = tClass.getDeclaredConstructors();
            Constructor<T> declaredConstructor = (Constructor<T>) declaredConstructors[0];
            ReflectionUtils.makeAccessible(declaredConstructor);
            Object[] parameterObjects = getParameterObjects(declaredConstructor, method);
            T t = declaredConstructor.newInstance(parameterObjects);

            // 获取类的字段
            Field[] declaredFields = tClass.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                int modifiers = declaredField.getModifiers();
                System.out.println(modifiers + "-" + declaredField.getName());
                // 过滤被 static final 修复的字段
                if (0x0010 == (0x0010 & modifiers)) {
                    System.out.println(modifiers + "----continues----" + declaredField.getName());
                    continue;
                }
                // 判断字段的类型。基本类型,包装类型,String,Date,自定义类型,
                Object instance = newInstance(method, declaredField.getType(), declaredField);
                ReflectionUtils.makeAccessible(declaredField);
                ReflectionUtils.setField(declaredField, t, instance);
                // 解析嵌套类型,判断字段类型。
            }
            return t;
        }
    }

    private static Object[] getParameterObjects(Constructor constructor, Method method) throws Exception {
        int parameterCount = constructor.getParameterCount();
        Parameter[] parameters = constructor.getParameters();
        Object[] objects = new Object[parameterCount];
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            if (BeanTypeUtil.isSimpleField(parameter.getType())) {
                objects[i] = BeanTypeUtil.getSimpleFieldValue(parameter.getType());
            } else {
                Type genericReturnType = method.getGenericReturnType();
                Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
                Type actualTypeArgument = actualTypeArguments[0];
                String typeName = actualTypeArgument.getTypeName();
                Class<?> aClass = Class.forName(typeName);
                Object instance = newInstance(method, aClass, null);
                objects[i] = instance;
            }
        }
        return objects;
    }

    /**
     * 解析接口
     *
     * @param tClass 目标类
     * @param <T>    指定类型T
     *
     * @return t
     */
    private static <T> T doParseInterface(Class<T> tClass) {
        return null;
    }

    /**
     * 解析Map
     *
     * @param tClass 目标类
     * @param <T>    指定类型T
     *
     * @return T
     */
    private static <T> T doParseMap(Class<T> tClass) {
        log.error("不支持Map,暂且给您返回null了,建议使用对象代替Map,然而，我们后续会支持的");
        return null;
    }

    /**
     * 解析集合
     *
     * @param tClass 目标类
     * @param <T>    指定类型T
     *
     * @return T
     */
    private static <T> T doParseCollection(Method method, Class<T> tClass, Field field) throws Exception {
        String canonicalName = tClass.getCanonicalName();
        Type genericType = null;
        if (null == field) {
            genericType = method.getGenericReturnType();
        } else {
            // 字段是list
            genericType = field.getGenericType();
        }

        Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
        if (actualTypeArguments.length == 0) {
            log.error("未指定泛型类型,oh，god, 请设置java的版本为1.4, 然后我会告诉你,不支持java版本1.4，请使用1.8！下一个！！！");
        }
        String genericClassName = (actualTypeArguments[0]).getTypeName();
        Class<?> aClass = Class.forName(genericClassName);
        Collection<Object> collection = new ArrayList<>();

        int i = RandomUtil.randomIntInTen();
        for (int j = 0; j < i; j++) {
            collection.add(newInstance(method, aClass, field));
        }
        Collection<Object> objects = null;
        if ("java.util.List".equals(canonicalName) || "java.util.ArrayList".equals(canonicalName)) {
            objects = Lists.newArrayList(collection);
        } else if ("java.util.LinkedList".equals(canonicalName)) {
            objects = Lists.newLinkedList();
            objects.addAll(collection);
        } else if ("java.util.TreeSet".equals(canonicalName)) {
            objects = new TreeSet<>();
            objects.addAll(collection);
        } else if ("java.util.Set".equals(canonicalName) || "java.util.HashSet".equals(canonicalName)) {
            objects = Sets.newHashSet(collection);
        } else {
            log.error("暂不支持出 ArrayList, LinkedList之外的类型");
        }
        return (T) objects;
    }

    /**
     * 解析数组类型
     *
     * @param tClass 目标类
     * @param <T>    指定类型T
     *
     * @return T
     */
    private static <T> T doParseArray(Method method, Class<T> tClass, Field field) throws Exception {
        String canonicalName = tClass.getCanonicalName();
        if (canonicalName.endsWith("[][]")) {
            throw new RuntimeException("目前不支持多维数据");
        }

        String className = canonicalName.replace("[]", "");
        Class<?> aClass = Class.forName(className);
        int length = RandomUtil.randomIntInTen();
        Object array = Array.newInstance(aClass, length);
        for (int i = 0; i < length; i++) {
            Array.set(array, i, newInstance(method, aClass, field));
        }
        return (T) array;
    }

}
